<?php

namespace app\logic\admin;

use ReflectionClass;

class L_adminFunc
{

    /*获取 全部id和方法名
     *
     */
    function getAllKeyVal()
    {
        $final_arr = logInit();
        $final_arr["result"] = dict();
        if ($final_arr["error_no"] == 0) {
            $Kv = array();
            $adManageResult = app("S_Admin_adminFunc")->getAll();
            foreach ($adManageResult["result"] as $item) {
                $Kv [$item["id"]] = $item["moduleName"] . "->" . $item["actionName"];
            }
            $final_arr["result"] = $Kv;
        }
        return $final_arr;
    }

    /*获取 全部功能json格式
     *
     */
    function getAllJson()
    {
        $final_arr = logInit();
        $final_arr["result"] = dict();

        if ($final_arr["error_no"] == 0) {
            $paramsObj = paramsObj();
            $paramsObj->params = array();
            $result = app("S_Admin_adminMenu")->getAll();
            if ($result["error_no"] === 0) {

                $menuJson = (new L_adminMenu())->buildTree($result["result"]);
                $menuJson["pid"] = 0;
            }
        }
        if ($final_arr["error_no"] == 0) {
            $result = app("S_Admin_adminFunc")->getAll();
            if ($result["error_no"] === 0) {
                $funcList = $result["result"];
            } else {
                $final_arr = logCallErrorMsg($final_arr, $result);
            }
        }


        // 菜单列表 和功能列表都有了,开始循环处理
        if ($final_arr["error_no"] == 0) {
            $menuJson[]=array("id"=>0,"pid"=>-1,"name"=>"无菜单","children"=>array());
            $funcList=$this->funcList2Arr($funcList);
            foreach ($menuJson as $key => $val) {
                $this->buildTree($menuJson[$key], $funcList);  //角色功能绑定 json有问题,继续解决 funcList2Arr 有问题
            }
            unset($menuJson["pid"]);
            $final_arr["result"] = $menuJson;
        }
        return $final_arr;
    }


    public function labelIsExisting($arr, $label): int
    {

        if ($arr === null) {
            return -1;
        }

        foreach ($arr as $key => $val) {
            if ($val->label === $label) {
                return $key;
            }
        }
        return -1;
    }


    //更新控制器功能列表
    public function updateControllerFunctionList($paramObj = "")
    {
        $dataObj = paramsObj();
        $dataObj->request = paramsObj();
        $dataObj->data = paramsObj();
        $dataObj->data->use_trans = false;
        $dataObj->result = array();
        $final_arr = logInit();
        $func = array();
        //获取全部菜单 id和名称数组
        $menuIds = array();
        $checkResult = app("L_Admin_adminMenu")->getAllKeyVal();
        if ($checkResult["error_no"] == 0) {
            $menuIds = $checkResult["result"];
        } else {
            $final_arr = logCallErrorMsg($final_arr, $checkResult);
        }

        //控制器方法反查路由
        $CA["get"] = array(); //控制器方法=>路由地址
        $CA["post"] = array(); //控制器方法=>路由地址
        $CA["put"] = array(); //控制器方法=>路由地址
        $CA["delete"] = array(); //控制器方法=>路由地址
        if ($final_arr["error_no"] == 0) {
            //获取路由信息 get 路由地址和 控制器 方法信息 数组
            $router = router()->routeMap["get"];
            foreach ($router as $key => $val) {
                $CA["get"][$val["controller"]] = $key;
            }
            //获取路由信息 get 路由地址和 控制器 方法信息 数组
            $router = router()->routeMap["post"];
            foreach ($router as $key => $val) {
                $CA["post"][$val["controller"]] = $key;
            }
            //获取路由信息 get 路由地址和 控制器 方法信息 数组
            $router = router()->routeMap["put"];
            foreach ($router as $key => $val) {
                $CA["put"][$val["controller"]] = $key;
            }
            //获取路由信息 get 路由地址和 控制器 方法信息 数组
            $router = router()->routeMap["delete"];
            foreach ($router as $key => $val) {
                $CA["delete"][$val["controller"]] = $key;
            }
        }
        //扫描系统自带控制器目录=======================================
        if ($final_arr["error_no"] == 0) {
            //获取文件夹内所有控制器类名
            $folderPath = LTCMS_ROOT . '/app/controller/admin'; // 替换为你的文件夹路径
            $phpFiles = glob($folderPath . '/*.php');
            $classNames = [];
            foreach ($phpFiles as $file) {
                $content = file_get_contents($file);
                preg_match_all('/class\s+(\w+)/', $content, $matches);
                $classNames = array_merge($classNames, $matches[1]);
            }
            //循环每个类
            foreach ($classNames as $className) {
                switch ($className) {
                    default:
                        $this->forClass($func, $menuIds, $CA, "app\\controller\\admin\\" . $className);
                        break;
                    case "Article" :
                        //获取文件夹内所有控制器类名
                        $checkResult = app("S_Admin_module")->allData();
                        if ($checkResult["error_no"] == 0) {
                            $moduleArr = $checkResult["result"];
                            //循环每个类
                            foreach ($moduleArr as $moduleModule) {
                                $this->forClassArticle($func, $menuIds, $CA, "app\\controller\\admin\\" . $className, $moduleModule);
                            }
                        }
                        break;
                    case "Category" :
                        //获取文件夹内所有控制器类名
                        $checkResult = app("S_Admin_module")->allData();
                        if ($checkResult["error_no"] == 0) {
                            $moduleArr = $checkResult["result"];
                            //循环每个类
                            foreach ($moduleArr as $moduleModule) {
                                $this->forClassCategory($func, $menuIds, $CA, "app\\controller\\admin\\" . $className, $moduleModule);
                            }
                        }
                        break;
                }
            }

        }
        //扫描 插件 配置信息内的 adminControllerPath 控制器目录=======================================
        if ($final_arr["error_no"] == 0) {
            //加载插件路由
            $checkResult = app("L_Common_plugins")->getEnabledPlugins();
            if ($checkResult["error_no"] == "0") {
                $plugin = $checkResult["result"];
                foreach ($plugin as $pval) {
                    $tempObj = getParamsObj();
                    $tempObj->params = array();
                    $tempObj->params["pluginId"] = $pval["pluginDir"];
                    $tempObj->params["action"] = "info";
                    $tempObj->params["className"] = "config";
                    $result = app("L_Common_plugins")->callFunc($tempObj);
                    if ($result["error_no"] == "0" && isset($result["result"]["adminControllerPath"])) { //有配置信息,并且有后台控制器路径才扫描
                        $pluginInfo = $result["result"];
                        //获取文件夹内所有控制器类名
                        $folderPath = LTCMS_ROOT . "/" . $pval["pluginDir"] . $pluginInfo["adminControllerPath"]; // 插件控制器目录
                        $phpFiles = glob($folderPath . '/*.php');
                        $classNames = [];
                        foreach ($phpFiles as $file) {
                            $content = file_get_contents($file);
                            preg_match_all('/class\s+(\w+)/', $content, $matches);
                            $classNames = array_merge($classNames, $matches[1]);
                        }
                        //循环每个类
                        foreach ($classNames as $className) {
                            $namespace = str_replace("/", "\\", $pval["pluginDir"] . $pluginInfo["adminControllerPath"]); //插件id+配置控制器目录]
                            $this->forClass($func, $menuIds, $CA, $namespace . "\\" . $className, $pval["pluginDir"]);
                        }
                    }
                }
            }
        }

        if ($final_arr["error_no"] == 0) {
            //获取到所有信息了,开始插入,如果控制器+方法+其他 已存在,就更新,如果不存在,就插入
            $ids = array(); //更新或插入,id都加入在这里,如果数据库id不在这个内,说明功能已删除,//先不删了,如果历史功能删了,角色绑定功能id找不到功能id,更懵逼,冗余
            $总数 = count($func);
            $更新成功 = 0;
            $更新失败 = 0;
            $插入成功 = 0;
            $插入失败 = 0;
            $数据相同 = 0;
            foreach ($func as $key => $val) {
                $tempObj = getParamsObj();
                $tempObj->params = $val;
                $result = app("S_Admin_adminFunc")->infoMAO($tempObj);
                if ($result["error_no"] === 0) {
                    $ids[] = $result["result"]["id"];
                    $tempObj->params["id"] = $result["result"]["id"];
                    if (array_equally($tempObj->params, $result["result"])) {
                        $数据相同 += 1;
                    } else {
                        //数据已存在,直接更新   // 可能存在用户已经修改名称的情况,所以已经存在的,不在更新
/*                        $result = app("S_Admin_adminFunc")->update($tempObj);
                        if ($result["error_no"] === 0) {
                            $更新成功 += 1;
                        } else {
                            $更新失败 += 1;
                        }*/
                    }

                } else {
                    //数据不存在,直接插入
                    $result = app("S_Admin_adminFunc")->store($tempObj);
                    if ($result["error_no"] === 0) {
                        $插入成功 += 1;
                        $ids[] = $result['result']["affected_rows"];
                    } else {
                        $插入失败 += 1;
                        $final_arr = logCallErrorMsg($final_arr, $result);
                        break;
                    }
                }

            }
            if ($final_arr["error_no"] == 0) {
                $final_arr["result"] = ["count" => $总数, "UpdateEqually" => $数据相同, "UpdateOk" => $更新成功, "UpdateFail" => $更新失败, "insertOk" => $插入成功, "insertFail" => $插入失败];
            }
        }

        return $final_arr;

    }


    //循环通用类 添加方法到功能列表
    function forClass(&$func, $menuIds, $CA, $class, $plugins = ""/*插件id*/)
    {
        $ref = new ReflectionClass($class);
        $cNote = $ref->getMethod('__construct'); //类备注
        /**
         * @menuName 后台权限
         */
        $menuName = trim(str_getBetween($cNote, "@menuName", "\n"));  //菜单名称
        $menuId = array_keys($menuIds, $menuName); //菜单id
        if (is_array($menuId)) {
            $menuId = $menuId[0]; //有菜单,直接赋值
        } else {
            $menuId = 0; //没菜单直接0
        }

        $module = $ref->getName(); //类控制器名称,
        $prefix = "app\controller\\";
        if (substr($module, 0, strlen($prefix)) === $prefix) {
            $module = substr($module, strlen($prefix));
        }
        $module = str_replace("\\", "/", $module);
        $moduleName = trim(str_getBetween($cNote, "@moduleName", "\n"));  //模块名称


        //$plugins = trim(str_getBetween($cNote, "@plugins", "\n"));  //插件名称

        $methods = $ref->getMethods();
        foreach ($methods as $method) {
            $action = $method->getName();  //类方法名
            if ($action === "__construct") { //跳过
                continue;
            }

            $aNote = $method->getDocComment(); //方法备注
            $actionName = trim(str_getBetween($aNote, "@actionName", "\n")) ?? $action;
            $show = trim(str_getBetween($aNote, "@show", "\n")) ?? 1;

            if ($show == 0) { //没配置备注,跳过
                continue;
            }

            $sort = trim(str_getBetween($aNote, "@sort", "\n"));

            if (!$sort) { //如果不指定,就按照类方法位置排序
                foreach ($methods as $index => $method2) {
                    if ($method2->getName() === $action) {
                        $sort = $index + 1; // 位置从 1 开始计数
                        break;
                    }
                }
            }


            $route = "";
            $routhAction = 5;
            if (isset($CA["get"][$module . "/" . $action])) {  //如果存在get路由就查
                $route = $CA["get"][$module . "/" . $action];
                $routhAction = 1;
            } else if (isset($CA["post"][$module . "/" . $action])) {
                $route = $CA["post"][$module . "/" . $action];
                $routhAction = 2;
            } else if (isset($CA["put"][$module . "/" . $action])) {
                $route = $CA["put"][$module . "/" . $action];
                $routhAction = 3;
            } else if (isset($CA["delete"][$module . "/" . $action])) {
                $route = $CA["delete"][$module . "/" . $action];
                $routhAction = 4;
            }

            /*            if ($route === "") { //没有路由地址的直接跳过   //暂时不跳过,方便检测代码是否有错误,比如大小写
                            continue;
                        }*/

            $temp = [
                "menuId" => $menuId,
                "routhAction" => $routhAction,
                "route" => $route,
                "module" => $module,  //实际是菜单名称,
                "moduleName" => $moduleName,  //实际是菜单名称,
                "action" => $action,
                "actionName" => $actionName,
                "other" => "",
                "isShow" => intval($show),
                "isEnable" => 1,            //暂时全部启用
                "sort" => intval($sort),
                "description" => "",
                "plugins" => $plugins,

            ];
            $func[] = $temp;
        }
    }


    //循环文章类  共用控制器添加方法
    function forClassArticle(&$func, $menuIds, $CA, $class, $articleInfo/*模型信息数组*/)
    {

        if (!isset($articleInfo["id"]) || !isset($articleInfo["module"]) || !isset($articleInfo["name"])) {
            return; //参数不对直接返回
        }
        if ($articleInfo["module"] != "article") {
            return; //不是文章的模型 跳过
        }


        $ref = new ReflectionClass($class);
        $cNote = $ref->getMethod('__construct'); //类备注
        /**
         * @menuName {name}管理
         * 上面的是菜单的名字 {name} 为变量 表 module.name 值
         * @moduleName {name}管理
         * 上面的是控制器的名字
         */
        $menuName = trim(str_getBetween($cNote, "@menuName", "\n"));  //菜单名称
        $menuName = str_replace("{name}", $articleInfo["name"], $menuName);
        $menuId = array_keys($menuIds, $menuName); //菜单id
        if (is_array($menuId)) {
            $menuId = $menuId[0]; //有菜单,直接赋值
        } else {
            $menuId = 0; //没菜单直接0
        }

        $module = $ref->getName(); //类控制器名称,
        $prefix = "app\controller\\";
        if (substr($module, 0, strlen($prefix)) === $prefix) {
            $module = substr($module, strlen($prefix));
        }
        $module = str_replace("\\", "/", $module);
        // 不是文章不处理==========================
        if ($module !== "admin/Article") {
            return;
        }


        $moduleName = trim(str_getBetween($cNote, "@moduleName", "\n"));  //模块名称
        $moduleName = str_replace("{name}", $articleInfo["name"], $moduleName);

        $plugins = trim(str_getBetween($cNote, "@plugins", "\n"));  //插件名称

        $methods = $ref->getMethods();
        foreach ($methods as $method) {
            $action = $method->getName();  //类方法名
            if ($action === "__construct") { //跳过
                continue;
            }

            $aNote = $method->getDocComment(); //方法备注
            $actionName = trim(str_getBetween($aNote, "@actionName", "\n")) ?? $action;
            $actionName = str_replace("{name}", $articleInfo["name"], $actionName);
            $show = trim(str_getBetween($aNote, "@show", "\n")) ?? 1;

            if ($show == 0) { //没配置备注,跳过
                continue;
            }

            $sort = trim(str_getBetween($aNote, "@sort", "\n"));

            if (!$sort) { //如果不指定,就按照类方法位置排序
                foreach ($methods as $index => $method2) {
                    if ($method2->getName() === $action) {
                        $sort = $index + 1; // 位置从 1 开始计数
                        break;
                    }
                }
            }


            $route = "";
            $routhAction = 5;
            if (isset($CA["get"][$module . "/" . $action])) {  //如果存在get路由就查
                $route = $CA["get"][$module . "/" . $action];
                //admin/article/indexRecycle?moduleId=19
                $route = $route . "?moduleId=" . $articleInfo["id"];
                $routhAction = 1;
            } else if (isset($CA["post"][$module . "/" . $action])) {
                $route = $CA["post"][$module . "/" . $action];
                $routhAction = 2;
            } else if (isset($CA["put"][$module . "/" . $action])) {
                $route = $CA["put"][$module . "/" . $action];
                $routhAction = 3;
            } else if (isset($CA["delete"][$module . "/" . $action])) {
                $route = $CA["delete"][$module . "/" . $action];
                $routhAction = 4;
            }

            /*            if ($route === "") { //没有路由地址的直接跳过   //暂时不跳过,方便检测代码是否有错误,比如大小写
                            continue;
                        }*/

            $temp = [
                "menuId" => $menuId,
                "routhAction" => $routhAction,
                "route" => $route,
                "module" => $module,  //实际是菜单名称,
                "moduleName" => $moduleName,  //实际是菜单名称,
                "action" => $action,
                "actionName" => $actionName,
                "other" => "moduleId=" . $articleInfo["id"],
                "isShow" => intval($show),
                "isEnable" => 1,            //暂时全部启用
                "sort" => intval($sort),
                "description" => "",
                "plugins" => $plugins,

            ];
            $func[] = $temp;


        }
    }

    //循环文章类别类 共用控制器添加方法
    function forClassCategory(&$func, $menuIds, $CA, $class, $articleInfo/*模型信息数组*/)
    {

        if (!isset($articleInfo["id"]) || !isset($articleInfo["module"]) || !isset($articleInfo["name"])) {
            return; //参数不对直接返回
        }
        if ($articleInfo["module"] != "article") {
            return; //不是文章的模型 跳过
        }


        $ref = new ReflectionClass($class);
        $cNote = $ref->getMethod('__construct'); //类备注
        /**
         * @menuName {name}管理
         * 上面的是菜单的名字 {name} 为变量 表 module.name 值
         * @moduleName {name}管理
         * 上面的是控制器的名字
         */
        $menuName = trim(str_getBetween($cNote, "@menuName", "\n"));  //菜单名称
        $menuName = str_replace("{name}", $articleInfo["name"], $menuName);
        $menuId = array_keys($menuIds, $menuName); //菜单id
        if (is_array($menuId)) {
            $menuId = $menuId[0]; //有菜单,直接赋值
        } else {
            $menuId = 0; //没菜单直接0
        }

        $module = $ref->getName(); //类控制器名称,
        $prefix = "app\controller\\";
        if (substr($module, 0, strlen($prefix)) === $prefix) {
            $module = substr($module, strlen($prefix));
        }
        $module = str_replace("\\", "/", $module);
        // 不是文章类别不处理==========================
        if ($module !== "admin/Category") {
            return;
        }


        $moduleName = trim(str_getBetween($cNote, "@moduleName", "\n"));  //模块名称
        $moduleName = str_replace("{name}", $articleInfo["name"], $moduleName);

        $plugins = trim(str_getBetween($cNote, "@plugins", "\n"));  //插件名称

        $methods = $ref->getMethods();
        foreach ($methods as $method) {
            $action = $method->getName();  //类方法名
            if ($action === "__construct") { //跳过
                continue;
            }

            $aNote = $method->getDocComment(); //方法备注
            $actionName = trim(str_getBetween($aNote, "@actionName", "\n")) ?? $action;
            $actionName = str_replace("{name}", $articleInfo["name"], $actionName);
            $show = trim(str_getBetween($aNote, "@show", "\n")) ?? 1;

            if ($show == 0) { //没配置备注,跳过
                continue;
            }

            $sort = trim(str_getBetween($aNote, "@sort", "\n"));

            if (!$sort) { //如果不指定,就按照类方法位置排序
                foreach ($methods as $index => $method2) {
                    if ($method2->getName() === $action) {
                        $sort = $index + 1; // 位置从 1 开始计数
                        break;
                    }
                }
            }


            $route = "";
            $routhAction = 5;
            if (isset($CA["get"][$module . "/" . $action])) {  //如果存在get路由就查
                $route = $CA["get"][$module . "/" . $action];
                //admin/article/indexRecycle?dataType=module_19
                $route = $route . "?dataType=module&dataId=" . $articleInfo["id"]; //get后缀需要增加这个参数
                $routhAction = 1;
            } else if (isset($CA["post"][$module . "/" . $action])) {
                $route = $CA["post"][$module . "/" . $action];
                $routhAction = 2;
            } else if (isset($CA["put"][$module . "/" . $action])) {
                $route = $CA["put"][$module . "/" . $action];
                $routhAction = 3;
            } else if (isset($CA["delete"][$module . "/" . $action])) {
                $route = $CA["delete"][$module . "/" . $action];
                $routhAction = 4;
            }

            /*            if ($route === "") { //没有路由地址的直接跳过   //暂时不跳过,方便检测代码是否有错误,比如大小写
                            continue;
                        }*/

            $temp = [
                "menuId" => $menuId,
                "routhAction" => $routhAction,
                "route" => $route,
                "module" => $module,  //实际是菜单名称,
                "moduleName" => $moduleName,  //实际是菜单名称,
                "action" => $action,
                "actionName" => $actionName,
                "other" => "dataType=module&dataId=" . $articleInfo["id"],
                "isShow" => intval($show),
                "isEnable" => 1,            //暂时全部启用
                "sort" => intval($sort),
                "description" => "",
                "plugins" => $plugins,

            ];
            $func[] = $temp;
        }
    }


    //递归菜单 控制器功能到菜单树下
    public function buildTree(&$data, $funcList/*二维数组[控制器名称][方法名称]*/)
    {
        if (isset($data["pid"])) { //存在pid 那就是菜单,直接递归子目录就行
            foreach ($funcList as $key => $val) {
                if ($data["id"] == $key) {
                    $arr2 = array();
                    foreach ($val as $k => $v) {
                        $arr2[] = array("id" => uniqid(), "label" => $k, "children" => $v);
                    }
                    $data["children"] = $arr2;
                }
            }
            $data["id"] = -$data["id"];
            $data["label"] = $data["name"];
            unset($data["name"]);
            foreach ($data["children"] as $item => $itemVal) {
                $this->buildTree($data["children"][$item], $funcList);
            }
        }

    }


    //功能列表转数组 [菜单id][控制器][功能]
    public function funcList2Arr($funcList)
    {

        $arr = array();
        /*        foreach ($funcList as $key => $val) {
                    if (isset($arr[$val["moduleName"]])){
                        continue;
                    }
                    $arr[$val["moduleName"]]["menuId"]=$val["menuId"];
                }*/
        // 循环加入方法
        foreach ($funcList as $key => $val) {
            $arr[$val["menuId"]][$val["moduleName"]][] = array("id" => $val["id"], "label" => $val["actionName"]."(".$val["action"].")", "menuId" => $val["menuId"]);
        }
        return $arr;
    }

}